package com.runvp.service.biz.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.runvp.common.config.DeviceConfig;
import com.runvp.common.constant.ConstantRedisKey;
import com.runvp.common.core.redis.DistributeRedisLock;
import com.runvp.common.core.redis.RedisCache;
import com.runvp.common.core.redis.RedisLockClient;
import com.runvp.common.core.text.Convert;
import com.runvp.common.enums.CargoUseStatus;
import com.runvp.common.enums.EnableStatus;
import com.runvp.common.enums.YesOrNo;
import com.runvp.common.exception.base.BaseException;
import com.runvp.common.util.ToolUtils;
import com.runvp.common.utils.DateUtils;
import com.runvp.common.utils.ShiroUtils;
import com.runvp.common.utils.validtion.CheckException;
import com.runvp.service.biz.domain.BizDevice;
import com.runvp.service.biz.domain.BizDeviceCargo;
import com.runvp.service.biz.domain.BizGoods;
import com.runvp.service.biz.mapper.BizDeviceCargoMapper;
import com.runvp.service.biz.mapper.BizDeviceMapper;
import com.runvp.service.biz.mapper.BizGoodsMapper;
import com.runvp.service.biz.service.IBizDeviceCargoService;
import com.runvp.service.out.OutUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;

/**
 * 设备端口Service业务层处理
 *
 * @author runvp
 * @date 2022-12-24
 */
@Slf4j
@Service
public class BizDeviceCargoServiceImpl implements IBizDeviceCargoService {
    @Autowired
    private BizDeviceCargoMapper bizDeviceCargoMapper;
    @Autowired
    private BizDeviceMapper deviceMapper;
    @Autowired
    private BizGoodsMapper goodsMapper;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private RedisLockClient lockClient;

    /**
     * 查询设备端口
     *
     * @param id 设备端口主键
     * @return 设备端口
     */
    @Override
    public BizDeviceCargo selectBizDeviceCargoById(Long id) {
        return bizDeviceCargoMapper.selectBizDeviceCargoById(id);
    }

    /**
     * 查询设备端口列表
     *
     * @param bizDeviceCargo 设备端口
     * @return 设备端口
     */
    @Override
    public List<BizDeviceCargo> selectBizDeviceCargoList(BizDeviceCargo bizDeviceCargo) {
        return bizDeviceCargoMapper.selectBizDeviceCargoList(bizDeviceCargo);
    }

    /**
     * 初始化端口
     *
     * @param deviceId
     */
    @Override
    public String initCargo(Long deviceId) {
        BizDevice device = deviceMapper.selectBizDeviceById(deviceId);
        CheckException.emptyThrowException(device, "设备不存在");
        BizDeviceCargo query = new BizDeviceCargo();
        query.setDeviceId(deviceId);
        List<BizDeviceCargo>  deviceCargos = selectBizDeviceCargoList(query);
        if(!CollectionUtils.isEmpty(deviceCargos)){
            throw new BaseException("端口已完成初始化,请勿重复操作");
        }
        int cargoNum = device.getMaxCargoLane();
        BizDeviceCargo cargo;
        for (int i = 1; i <= cargoNum; i++) {
            cargo = new BizDeviceCargo();
            cargo.setNumber(i);
            cargo.setDeviceId(deviceId);
            cargo.setDeviceSn(device.getDeviceCode());
            cargo.setCapacity(10);
            cargo.setUseStatus(CargoUseStatus.IDLE.getCode());
            cargo.setStatus(EnableStatus.ENABLE.getCode());
            cargo.setCreateBy(ShiroUtils.getLoginName());
            insertBizDeviceCargo(cargo);
        }
        return device.getDeviceCode();
    }
    /**
     * 初始化端口
     *
     * @param deviceId
     */
    @Override
    public void sendFee(Long deviceId) {
        BizDevice device = deviceMapper.selectBizDeviceById(deviceId);
        CheckException.emptyThrowException(device, "设备不存在");
        BizDeviceCargo query = new BizDeviceCargo();
        query.setDeviceId(deviceId);
        List<BizDeviceCargo> cargos =  selectBizDeviceCargoList(query);
        JSONObject map = new JSONObject();
        if(CollectionUtils.isEmpty(cargos)){
            throw new BaseException("收费方案为空");
        }
        for(BizDeviceCargo cargo:cargos){
            map.put("pr"+(cargo.getNumber()-1),cargo.getGoodsPrice());
        }
        //执行消息推送
        boolean flag = OutUtil.sendCmd(DeviceConfig.getSendFeeUrl(),device.getDeviceCode(),map.toJSONString());
        log.info("收费方案下发结果【{}】",flag);
        if(!flag){
            throw new BaseException("收费方案下发失败");
        }
    }
    /**
     * 初始化端口
     *
     * @param deviceSn
     */
    @Override
    public void sendFee(String deviceSn) {
        BizDevice device = deviceMapper.selectBizDeviceBySn(deviceSn);
        CheckException.emptyThrowException(device, "设备不存在");
        BizGoods query = new BizGoods();
        query.setDeviceSn(deviceSn);
        List<BizGoods> goods =  goodsMapper.selectBizGoodsList(query);
        JSONObject map = new JSONObject();
        if(CollectionUtils.isEmpty(goods)){
            throw new BaseException("收费方案为空");
        }
        for (int i = 0; i < goods.size(); i++) {
            BizGoods data = goods.get(i);
            map.put(data.getBarCode(),data.getPrice());
        }
        //执行消息推送
        boolean flag = OutUtil.sendCmd(DeviceConfig.getSendFeeUrl(),device.getDeviceCode(),map.toJSONString());
        log.info("收费方案下发结果【{}】",flag);
        if(!flag){
            throw new BaseException("收费方案下发失败");
        }
    }
    /**
     * 一键补满
     *
     * @param deviceId
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void replenish(Long deviceId) {
        BizDeviceCargo query = new BizDeviceCargo();
        query.setDeviceId(deviceId);
        List<BizDeviceCargo> cargos = selectBizDeviceCargoList(query);
        if (CollectionUtils.isEmpty(cargos)) {
            return;
        }
        for (BizDeviceCargo cargo : cargos) {
            if(ToolUtils.toInt(cargo.getGoodsId()) == 0){
                log.warn("端口【{}】未上架产品,跳过补货",cargo.getNumber());
                continue;
            }
            cargo.setGoodsStock(cargo.getCapacity());
            cargo.setUpdateBy(ShiroUtils.getLoginName());
            updateBizDeviceCargo(cargo);
        }
    }
    /**
     * 刷新大屏商品列表
     * @param deviceId
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void refreshList(Long deviceId){
        BizDevice device = deviceMapper.selectBizDeviceById(deviceId);
        if(null == device){
            throw new BaseException("设备不存在");
        }
        String refreshKey = ConstantRedisKey.PRODUCT_REFRESH+device.getDeviceCode();
        redisCache.setCacheObject(refreshKey, YesOrNo.YES.getCode());
    }
    /**
     * 充电开启测试
     * @param id
     * @return boolean
     */
    @Override
    public synchronized boolean chargeStart(Long id){
        BizDeviceCargo cargo = selectBizDeviceCargoById(id);
        CheckException.emptyThrowException(cargo,"端口异常");
        JSONObject param = new JSONObject();
        param.put("amt",1);
        param.put("po",cargo.getNumber());
        param.put("oid", String.valueOf(cargo.getId()));
        boolean res = OutUtil.out(cargo.getDeviceSn(),param.toJSONString());
        if(res){
            //库存-1
            cargo.setUpdateBy(ShiroUtils.getLoginName());
            updateBizDeviceCargo(cargo);
        }else {
            throw new BaseException("充电启动失败");
        }
        return res;
    }
    /**
     * 充电停止测试
     * @param id
     * @return boolean
     */
    @Override
    public synchronized boolean chargeEnd(Long id){
        BizDeviceCargo cargo = selectBizDeviceCargoById(id);
        CheckException.emptyThrowException(cargo,"端口异常");
        JSONObject param = new JSONObject();
        param.put("po",cargo.getNumber());
        param.put("oid", String.valueOf(cargo.getId()));
        boolean res = OutUtil.stop(cargo.getDeviceSn(),param.toJSONString());
        if(res){
            cargo.setUpdateBy(ShiroUtils.getLoginName());
            updateBizDeviceCargo(cargo);
        }else {
            throw new BaseException("充电停止失败");
        }
        return res;
    }

    /**
     * 新增设备端口
     *
     * @param bizDeviceCargo 设备端口
     * @return 结果
     */
    @Override
    public int insertBizDeviceCargo(BizDeviceCargo bizDeviceCargo) {
        bizDeviceCargo.setCreateTime(DateUtils.getNowDate());
        return bizDeviceCargoMapper.insertBizDeviceCargo(bizDeviceCargo);
    }
    /**
     * 新增设备端口
     *
     * @param bizDeviceCargo 设备端口
     * @return 结果
     */
    @Override
    public int createBizDeviceCargo(BizDeviceCargo bizDeviceCargo) {
        BizDevice device = deviceMapper.selectBizDeviceById(bizDeviceCargo.getDeviceId());
        if(null == device){
            throw new BaseException("设备不存在");
        }
        bizDeviceCargo.setDeviceSn(device.getDeviceCode());
        BizDeviceCargo cargo = bizDeviceCargoMapper.selectBizDeviceCargoBySnAndNumber(bizDeviceCargo);
        if(null != cargo){
            throw new BaseException("端口编号【"+bizDeviceCargo.getNumber()+"】已存在");
        }
        if(StringUtils.isBlank(bizDeviceCargo.getStatus())){
            bizDeviceCargo.setStatus(EnableStatus.ENABLE.getCode());
        }
        bizDeviceCargo.setCapacity(10);
        bizDeviceCargo.setUseStatus(CargoUseStatus.IDLE.getCode());
        bizDeviceCargo.setCreateBy(ShiroUtils.getLoginName());
        bizDeviceCargo.setCreateTime(DateUtils.getNowDate());
        return bizDeviceCargoMapper.insertBizDeviceCargo(bizDeviceCargo);
    }
    /**
     * 修改设备端口
     *
     * @param bizDeviceCargo 设备端口
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int updateBizDeviceCargo(BizDeviceCargo bizDeviceCargo) {
        bizDeviceCargo.setUpdateTime(DateUtils.getNowDate());
        handleGoods(bizDeviceCargo);
        if (ToolUtils.toInt(bizDeviceCargo.getGoodsStock()) > ToolUtils.toInt(bizDeviceCargo.getCapacity())) {
            throw new BaseException("库存不能大于端口容量");
        }
        int r = bizDeviceCargoMapper.updateBizDeviceCargo(bizDeviceCargo);
        return r;
    }
    /**
     * 修改端口状态 使用中/空闲
     * @param id
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int usePort(Long id,String useStatus){
        DistributeRedisLock redisLock = lockClient.getRedisLock("usePort:"+id);
        try {
            redisLock.lock();
            BizDeviceCargo cargo = selectBizDeviceCargoById(id);
            if(null == cargo){
                log.error("ID:【{}】端口不存在",id);
                return 0;
            }
            cargo.setUseStatus(useStatus);
            return updateBizDeviceCargo(cargo);
        }catch (Exception e){
            log.error("端口状态修改失败:{}",e.getMessage());
            return 0;
        }finally {
            redisLock.unlock();
        }
    }

    private void handleGoods(BizDeviceCargo bizDeviceCargo) {
        Long goodsId = bizDeviceCargo.getGoodsId();
        if (null == goodsId) {
            return;
        }
        BizGoods goods = goodsMapper.selectBizGoodsById(goodsId);
        if (null == goods) {
            return;
        }
        bizDeviceCargo.setGoodsName(goods.getName());
        bizDeviceCargo.setGoodsDiagram(goods.getDiagram());
        bizDeviceCargo.setGoodsCategory(goods.getCategoryId());
        if (bizDeviceCargo.getGoodsPrice() == null) {
            bizDeviceCargo.setGoodsPrice(goods.getPrice());
        }
        if (bizDeviceCargo.getGoodsCostPrice() == null) {
            bizDeviceCargo.setGoodsCostPrice(goods.getCostPrice());
        }
    }

    /**
     * 批量删除设备端口
     *
     * @param ids 需要删除的设备端口主键
     * @return 结果
     */
    @Override
    public int deleteBizDeviceCargoByIds(String ids) {
        return bizDeviceCargoMapper.deleteBizDeviceCargoByIds(Convert.toStrArray(ids));
    }

    /**
     * 删除设备端口信息
     *
     * @param id 设备端口主键
     * @return 结果
     */
    @Override
    public int deleteBizDeviceCargoById(Long id) {
        return bizDeviceCargoMapper.deleteBizDeviceCargoById(id);
    }
}
